#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>

#define NUM 1024            // 最长命令字符数
#define ARGV_NUM 32         // 最多命令和选项

char LineCommand[NUM];      // 存放命令
char* myargv[ARGV_NUM];     // 分割命令和选项


int last_code;      // 最近一次的退出码
int sig_num;        // 进程退出信号

// 分割当前工作路径
const char* getpath(char *path)
{
    int len = strlen(path);

    if(1 == len)
    {
        return "/";
    }


    int i = len - 1;
    while(path[i] != '/') i--;

    if(strcmp(path + i + 1, getenv("USER")) == 0)
    {
        return "~";
    }

    return path + i + 1;
}


int main()
{
    while(1)
    {
        // 用来存放当前工作路径
        char buf[64];                                                                                                                            
        /* 使用getcwd获取启动目录 */
        if (NULL == getcwd(buf, sizeof(buf))) {
            fprintf(stderr, "getcwd error: %s", strerror(errno));
            exit(1);
        }

        // 打印提示符
    
        char *hostname=strtok(getenv("HOSTNAME"),".");
        
        // 最终打印
        printf("[%s@%s %s]$$ ",getenv("USER"),hostname,getpath(buf));
        fflush(stdout);     // 刷新缓冲区


        // 获取命令及选项参数
        char *s = fgets(LineCommand,sizeof(LineCommand)-1,stdin);
        
        assert(s != NULL);
        
        (void)s;
        
        // 将最后一个字符'\n'置为0(NULL)
        LineCommand[ strlen(LineCommand) - 1 ] = 0;



        // 切分命令参数这个字符串
        myargv[0]=strtok(LineCommand," ");

        int i = 1;
        
        if(myargv[0] != NULL && strcmp("ls",myargv[0]) == 0)
        {
            myargv[i++] = (char*)"--color=auto";
        }
        
        while(myargv[i++] = strtok(NULL," "));
        

        if(
            myargv[0] != NULL &&
            myargv[1] != NULL && 
            strcmp("ll",myargv[0]) == 0 &&
            ( strcmp("-a",myargv[1]) == 0 || strcmp("-al",myargv[1]) == 0 || strcmp("-la",myargv[1]) == 0 )
        )
        {
            myargv[0] = (char*)"ls";
            myargv[1] = (char*)"-al";
            myargv[2] = (char*)"--color=auto";
        }


        if(myargv[0] != NULL && strcmp("ll",myargv[0]) == 0)
        {
            myargv[0] = (char*)"ls";
            myargv[1] = (char*)"-l";
            myargv[2] = (char*)"--color=auto";
        }


        // 内建命令-cd
        if(myargv[0] != NULL && strcmp("cd",myargv[0]) == 0)
        {

            // 用来存放前一次工作路径
            char prev_path[128];
            char cur_path[128];
            
            // cd -
            if(myargv[1] != NULL && strcmp("-",myargv[1]) == 0)
            {

                if (NULL == getcwd(cur_path, sizeof(cur_path))) {
                    fprintf(stderr, "getcwd error: %s", strerror(errno));
                    exit(1);
                }

                chdir(prev_path);
                
                strcpy(prev_path, cur_path);
                continue;
            }
                

            // cd ~
            if(myargv[1] != NULL && strcmp("~",myargv[1]) == 0)
            {

                /* 使用getcwd获取启动目录 */
                if (NULL == getcwd(prev_path, sizeof(prev_path))) {
                    fprintf(stderr, "getcwd error: %s", strerror(errno));
                    exit(1);
                }

                chdir(getenv("HOME"));
                continue;
            }
            

            // cd
            if(myargv[1] != NULL)
            {
                                
                /* 使用getcwd获取启动目录 */
                if (NULL == getcwd(prev_path, sizeof(prev_path))) {
                    fprintf(stderr, "getcwd error: %s", strerror(errno));
                    exit(1);
                }

                chdir(myargv[1]);
                continue;
            }
        }



        // 内建命令-echo
        if(myargv[0]!=NULL && myargv[1]!=NULL && strcmp("echo",myargv[0])==0)
        {

            if(strcmp("$?",myargv[1]) == 0)
            {
                printf("exit_code:%d,sig_num:%d\n",last_code,sig_num);
            }
            else
            {
                printf("%s\n",myargv[1]);
            }
          
            last_code = 0;
          
            continue;
        }



#ifdef DEBUG
        // 测试打印命令和选项分割情况
        for(int i = 0; myargv[i]; i++)
        {
            printf("myargv[%d]:%s\n",i,myargv[i]);
        }
#endif



        // 创建子进程--->执行命令
        pid_t id = fork();
        assert(id != -1);
        
        if(id == 0)
        {
            // child
            execvp(myargv[0],myargv);

            perror("exec");

            exit(1);        // 执行失败时退出码为1
        }


        // 父进程等待-阻塞时等待
        int status = 0;
        
        pid_t ret = waitpid(id, &status, 0);
        assert(ret > 0);
        (void)ret;

        last_code = (status>>8) & 0xFF;
        
        sig_num = status & 0x7F;

    }

    return 0;
}
